#include <errno.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <mysql.h>

#include "compat.h"

#include "psd_modules.h"
#include "psd_session.h"
#include "psd_config.h"
#include "psd_event.h"
#include "psd_measurement.h"
#include "psd_logger.h"
#include "psd_stats.h"

psdModule *module_info();
int psd_mysql_stats_init();
static void psd_mysql_stats_read_config();
static int connect_mysql();
static int psd_mysql_stats_save(psdSessionStats *stats);

static MYSQL *mysql;

static psdModule psd_mysql_stats_module = {
	.desc = "MySQL Statistics Backend",
	.dependencies = "",
	.init = psd_mysql_stats_init
};

static psdStatsBackend mysql_backend = {
	.name = "MySQL",
	.read_stats = NULL,
	.save_stats = psd_mysql_stats_save,
};

struct psd_mysql_stats_config_t {
	const char *server;
	unsigned int database_port;
	const char *user;
	const char *password;
	const char *database_name;
	const char *database_table;

};

static struct psd_mysql_stats_config_t psdMySQLStatsConfig = {
	.server = NULL,
	.database_port = 0,
	.user = NULL,
	.password = NULL,
	.database_name = "phoebus",
	.database_table = "phoebus_stats"
};

psdModule *module_info() {
	return &psd_mysql_stats_module;
}

int psd_mysql_stats_init() {
	char query[2048];
	
	psd_mysql_stats_read_config();

	mysql = mysql_init(NULL);
	if (!mysql) {
		psd_err(0, "couldn't initialize mysql structure");
		goto error_exit;
	}

	if (connect_mysql()) {
		psd_err(0, "couldn't connect to database");
		goto error_exit2;
	}

	snprintf(query, sizeof(query), "CREATE TABLE IF NOT EXISTS %s (session_id VARCHAR(32), user VARCHAR(30), email VARCHAR(30), institution VARCHAR(255), parent VARCHAR(255), child VARCHAR(255), end_time DOUBLE, duration DOUBLE, bytes_read BIGINT, bytes_written BIGINT, read_rate DOUBLE, write_rate DOUBLE)", psdMySQLStatsConfig.database_table);
	if (mysql_real_query(mysql, query, strlen(query)) != 0) {
		psd_err(0, "couldn't create statistics table: %s", mysql_error(mysql));
		goto error_exit2;
	}

	if (psd_set_stats_backend(&mysql_backend)) {
		psd_err(0, "couldn't register stats callback");
		goto error_exit2;
	}

	return 0;

error_exit2:
	mysql_close(mysql);
error_exit:
	return -1;
}

static int connect_mysql() {
	if (mysql_real_connect(mysql,psdMySQLStatsConfig.server,psdMySQLStatsConfig.user,psdMySQLStatsConfig.password,psdMySQLStatsConfig.database_name,psdMySQLStatsConfig.database_port,NULL,0) == NULL)
		return -1;

	return 0;
}

static void psd_mysql_stats_read_config() {
	int val;
	char *str_val;

	if (psd_depot_settings_get("mysql_stats", "db_server", &str_val) == 0) {
		psdMySQLStatsConfig.server = str_val;
	}

	if (psd_depot_settings_get_int("mysql_stats", "db_port", &val) == 0) {
		if (val >= 0)
			psdMySQLStatsConfig.database_port = val;
	}

	if (psd_depot_settings_get("mysql_stats", "db_username", &str_val) == 0) {
		psdMySQLStatsConfig.user = str_val;
	}

	if (psd_depot_settings_get("mysql_stats", "db_password", &str_val) == 0) {
		psdMySQLStatsConfig.password = str_val;
	}

	if (psd_depot_settings_get("mysql_stats", "db_name", &str_val) == 0) {
		psdMySQLStatsConfig.database_name = str_val;
	}

	if (psd_depot_settings_get("mysql_stats", "db_table", &str_val) == 0) {
		psdMySQLStatsConfig.database_table = str_val;
	}
}

static int psd_mysql_stats_save(psdSessionStats *stats) {
	char query[2048];

	if (mysql_ping(mysql)) {
		psd_err(0, "connection to %s failed: %s", psdMySQLStatsConfig.server, mysql_error(mysql));
		return 0;
	}

	snprintf(query, sizeof(query), "INSERT INTO %s VALUES('%s', '%s', '%s', '%s', '%s', '%s', %f, %f, %llu, %llu, %f, %f)",
			psdMySQLStatsConfig.database_table,
			stats->session_id,
			stats->username,
			stats->email,
			stats->institution,
			stats->upstream_conns,
			stats->downstream_conns,
			stats->end_time,
			stats->duration,
			stats->bytes_read,
			stats->bytes_written,
			stats->read_rate,
			stats->write_rate);

	if (mysql_real_query(mysql, query, strlen(query)) != 0) {
		psd_err(0, "MySQL write failed: %s", mysql_error(mysql));
	}

	return 0;
}
